#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/*
#define MAX_SUPPORT_RESOLUTION_X        4096
#define MAX_SUPPORT_RESOLUTION_X_DIV3   (MAX_SUPPORT_RESOLUTION_X / 3)
#define MAX_SUPPORT_RESOLUTION_Y        3122

typedef struct _SPLIPT_PARAM {
    char name[16];
    unsigned int  width;
    unsigned int height;
    unsigned int widthOut;
    unsigned int gap;
} SPLIT_PARAM;

const SPLIT_PARAM gSplitParam[] = {
    {
        "720p",     // name
        1280,       // width
        720,        // height
        404,        // split width for Y
        34,         // gap width for Y
    },
    {
        "1080p",     // name
        1920,        // width
        1080,        // height
        608,         // split width for Y
        48,          // gap width for Y
    },
    {
        "2160p",     // name
        3840,        // width
        2160,        // height
        1214,         // split width for Y
        99,          // gap width for Y
    },
};

#define SPLIT_PARAM_SIZE    (sizeof(gSplitParam)/sizeof(SPLIT_PARAM))

static int getParamIndex(char *name) {
    int i;

    for (i=0; i<SPLIT_PARAM_SIZE; i++) {
        if (strcmp(name, gSplitParam[i].name) == 0) {
            return i;
        }
    }

    return -1;
}
*/

static int split3(unsigned char *bufOrig,
        unsigned char *bufLeft, 
        unsigned char *bufCenter, 
        unsigned char *bufRight,
        const int width, 
        const int height, 
        const int widthOut, 
        const int widthGap) {
    int i,j;
    const int boundaryA = widthOut + widthGap;
    const int boundaryB = widthOut * 2 + widthGap * 2;
    int newI;

    for (i=0; i<width; i++) {
        if (i<widthOut) {
            // within the region of Left Panel
            for (j=0; j<height; j++) {
                bufLeft[i*height + height-1 - j] = bufOrig[j*width + i];
                //bufLeft[j*widthOut + i] = bufOrig[j*width + i];
            }
        } else if (i >= boundaryA && i<(boundaryA + widthOut)) {
            // within the region of Center panel
            newI = i - boundaryA;
            for (j=0; j<height; j++) {
                bufCenter[newI*height + height-1 - j] = bufOrig[j*width + i];
                //bufCenter[j*widthOut + newI] = bufOrig[j*width + i];
            }
        } else if (i >= boundaryB) {
            // within the region of Right panel
            newI = i - boundaryB;
            for (j=0; j<height; j++) {
                bufRight[newI*height + height-1 - j] = bufOrig[j*width + i];
                //bufRight[j*widthOut + newI] = bufOrig[j*width + i];
            }
        }
    }

    return 0;
}
    
unsigned char *bufOrig;
unsigned char *bufLeft;
unsigned char *bufCenter;
unsigned char *bufRight;

int main(int argc, char *argv[]) {

    FILE *fpOrig;
    FILE *fpLeft;
    FILE *fpCenter;
    FILE *fpRight;
    size_t freadNum;

    int i;

    unsigned int  width;
    unsigned int height;
    unsigned int widthOut;
    unsigned int gap;

    if (argc != 8) {
        printf("input error\n");
        printf("%s input_file width height width_output outLeft_file outCenter_file outRight_file\n", argv[0]);
        printf("example: %s example.yuv 1280 720 404 l.yuv c.yuv r.yuv\n", argv[0]);
        return -2;
    }

    width = atoi(argv[2]);
    height = atoi(argv[3]);
    widthOut = atoi(argv[4]);
    gap = (width - widthOut*3)/2;
    
    if (strcmp(argv[1], "stdin") == 0) {
        fpOrig = stdin;
    } else {
        fpOrig = fopen(argv[1], "rb");
    }

    if (fpOrig == NULL) {
        printf("can not open input file\n");
        return -1;
    }

    size_t bufSize = width*height;

    bufOrig = malloc(bufSize);
    if (bufOrig == NULL) {
        printf("not enough memory\n");
        fclose(fpOrig);
        return -3;
    }

    bufSize = bufSize / 3;

    bufLeft = malloc(bufSize);
    if (bufLeft == NULL) {
        free(bufOrig);
        printf("not enough memory\n");
        fclose(fpOrig);
        return -3;
    }

    bufCenter = malloc(bufSize);
    if (bufCenter == NULL) {
        free(bufOrig);
        free(bufLeft);
        printf("not enough memory\n");
        fclose(fpOrig);
        return -3;
    }

    bufRight = malloc(bufSize);
    if (bufRight == NULL) {
        free(bufOrig);
        free(bufLeft);
        free(bufCenter);
        printf("not enough memory\n");
        fclose(fpOrig);
        return -3;
    }

    fpLeft = fopen(argv[5], "wb");
    fpCenter = fopen(argv[6], "wb");
    fpRight = fopen(argv[7], "wb");

    do {
        // Read Y
        freadNum = fread(bufOrig, 1, width * height, fpOrig);
        if (freadNum != 0) {
            // Split Y
            split3(bufOrig, bufLeft, bufCenter, bufRight, 
                width, height, widthOut, gap);
            fwrite(bufLeft, 1, widthOut * height, fpLeft);
            fwrite(bufCenter, 1, widthOut * height, fpCenter);
            fwrite(bufRight, 1, widthOut * height, fpRight);
            
            for (i=0; i<2; i++) {
                // Read UV
                freadNum = fread(bufOrig, 1, (width/2) * (height/2), fpOrig);
                if (freadNum != 0) {
                    // Split UV
                    split3(bufOrig, bufLeft, bufCenter, bufRight, 
                        width/2, height/2, widthOut/2, gap/2);
                    fwrite(bufLeft, 1, (widthOut/2) * (height/2), fpLeft);
                    fwrite(bufCenter, 1, (widthOut/2) * (height/2), fpCenter);
                    fwrite(bufRight, 1, (widthOut/2) * (height/2), fpRight);
                }
            }
        }
    } while (freadNum != 0);
    if (strcmp(argv[1], "stdin") != 0) {
        fclose(fpOrig);
    }

    free(bufOrig);
    free(bufLeft);
    free(bufCenter);
    free(bufRight);
    fclose(fpLeft);
    fclose(fpCenter);
    fclose(fpRight);
    return 0;
}
